'''
Created on 14/05/2009

@author: eh01
'''
from yarra.datastore.dso import DSO
from yarra.datastore.dst import DST
from yarra.datastore.dscache import DSCache, DSCacheException,\
    DSCacheNotFoundException
import datetime
import unittest

VERSION_ONE = 1
VERSION_TWO = 2

class DSCacheTest(unittest.TestCase):

    def get_dummy_unsaved_dso_1(self):
        dst1 = DST(subject="dummySubject1", predicate="dummyPredicate1", object=None, literal="123", literal_type="int", xml_string=None)
        dst2 = DST(subject="dummySubject1", predicate="dummyPredicate2", object=None, literal="456", literal_type="int", xml_string=None)
        dso = DSO(version=VERSION_ONE, created_timestamp=datetime.datetime.now())
        dso.type = "DummyDSO1"
        dso.uri = "/dummy/object1/uri"
        dso.add_dsts([dst1, dst2])
        return dso
    
    def get_dummy_unsaved_dso_2(self):
        dst1 = DST(subject="dummySubject1", predicate="dummyPredicate1", object=None, literal="123", literal_type="int", xml_string=None)
        dst2 = DST(subject="dummySubject1", predicate="dummyPredicate2", object=None, literal="456", literal_type="int", xml_string=None)
        dso = DSO(id=1, created_timestamp=datetime.datetime.now())
        dso.type = "DummyDSO1"
        dso.uri = "/dummy/object1/uri"
        dso.add_dsts([dst1, dst2])
        return dso 
       
    def get_dummy_unsaved_dso_3(self):
        dst1 = DST(subject="dummySubject1", predicate="dummyPredicate1", object=None, literal="123", literal_type="int", xml_string=None)
        dst2 = DST(subject="dummySubject1", predicate="dummyPredicate2", object=None, literal="456", literal_type="int", xml_string=None)
        dso = DSO(created_timestamp=datetime.datetime.now())
        dso.type = "DummyDSO1"
        dso.uri = "/dummy/object1/uri"
        dso.add_dsts([dst1, dst2])
        return dso        
    
    def get_dummy_saved_dso_1_1(self):
        dst1 = DST(subject="dummySubject1", predicate="dummyPredicate1", object=None, literal="123", literal_type="int", xml_string=None)
        dst2 = DST(subject="dummySubject1", predicate="dummyPredicate2", object=None, literal="456", literal_type="int", xml_string=None)
        dst3 = DST(subject="dummySubject2", predicate="dummyPredicate3", object=None, literal="789", literal_type="int", xml_string=None)
        dso = DSO(id=1, version=VERSION_ONE, created_timestamp=datetime.datetime.now())
        dso.type = "DummyDSO1"
        dso.uri = "/dummy/object1/uri"
        dso.add_dsts([dst1, dst2, dst3])
        return dso    
    
    def get_dummy_saved_dso_1_2(self):
        dst1 = DST(subject="dummySubject1", predicate="dummyPredicate1", object=None, literal="123", literal_type="int", xml_string=None)
        dst2 = DST(subject="dummySubject1", predicate="dummyPredicate2", object=None, literal="456", literal_type="int", xml_string=None)
        dst3 = DST(subject="dummySubject2", predicate="dummyPredicate3", object=None, literal="789", literal_type="int", xml_string=None)
        dso = DSO(id=1, version=VERSION_TWO, created_timestamp=datetime.datetime.now())
        dso.type = "DummyDSO1"
        dso.uri = "/dummy/object1/uri"
        dso.add_dsts([dst1, dst2, dst3])
        return dso
    
    def get_dummy_saved_dso_2_1(self):
        dst1 = DST(subject="dummySubject1", predicate="dummyPredicate1", object=None, literal="123", literal_type="int", xml_string=None)
        dst2 = DST(subject="dummySubject1", predicate="dummyPredicate2", object=None, literal="456", literal_type="int", xml_string=None)
        dst3 = DST(subject="dummySubject2", predicate="dummyPredicate3", object=None, literal="789", literal_type="int", xml_string=None)
        dso = DSO(id=2, version=VERSION_ONE, created_timestamp=datetime.datetime.now())
        dso.type = "DummyDSO1"
        dso.uri = "/dummy/object2/uri"
        dso.add_dsts([dst1, dst2, dst3])
        return dso  

    def setUp(self):
        pass


    def tearDown(self):
        pass

    def test_save_case_1(self):
        """ Tests the dso is saved in cache successfully """
        ds_cache = DSCache()
        dso = self.get_dummy_saved_dso_1_1()
        dso = ds_cache.save([dso])[0]
        if dso:
            assert True
        else:
            self.fail("Persist failed")        

    def test_save_case_2(self):
        """ Tests saving a dso without a id """
        ds_cache = DSCache()
        dso = self.get_dummy_unsaved_dso_1()
        try:
            ds_cache.save([dso])
            self.fail('Shouldnt be able to save a dso in cache without an id')
        except DSCacheException:
            assert True

    def test_save_case_3(self):
        """ Tests saving a dso without a version """
        ds_cache = DSCache()
        dso = self.get_dummy_unsaved_dso_2()
        try:
            ds_cache.save([dso])
            self.fail('Shouldnt be able to save a dso in cache without an version')
        except DSCacheException:
            assert True   
            
    def test_save_case_4(self):
        """ Tests saving a dso without a id and version """
        ds_cache = DSCache()
        dso = self.get_dummy_unsaved_dso_3()
        try:
            ds_cache.save([dso])
            self.fail('Shouldnt be able to save a dso in cache without an id and version')
        except DSCacheException:
            assert True                        
     
    def test_save_case_5(self):
        """ Tests saving more than one dso """
        ds_cache = DSCache()
        dso1 = self.get_dummy_saved_dso_1_1()
        dso2 = self.get_dummy_saved_dso_2_1()
        dsos = ds_cache.save([dso1, dso2])
        if dsos and len(dsos) == 2:
            assert True
        else:
            self.fail('Save failed')
    
    def test_save_case_6(self):
        """ Tests saving two dsos, the second one without an id """
        ds_cache = DSCache()
        dso1 = self.get_dummy_saved_dso_1_1()
        dso2 = self.get_dummy_unsaved_dso_2()
        try:
            ds_cache.save([dso1, dso2])
        except DSCacheException:
            try:
                ds_cache.find_by_id_and_version(dso1.id, dso1.version)
                self.fail('Should raise a exception as the first dso shouldnt have been saved')
            except:
                assert True
    
    def test_save_case_7(self):
        """ Tests saving a dso adds it to the id and version map """
        ds_cache = DSCache()
        dso1 = self.get_dummy_saved_dso_1_1()
        ds_cache.save([dso1])
        dso = ds_cache.find_by_id_and_version(dso1.id, dso1.version)
        if dso:
            assert True
        else:
            self.fail('Save or Find failed')
            
    def test_save_case_8(self):
        """ Tests saving a dso adds it to the uri and version map """
        ds_cache = DSCache()
        dso1 = self.get_dummy_saved_dso_1_1()
        ds_cache.save([dso1])
        dso = ds_cache.find_by_URI_and_version(dso1.uri, dso1.version)
        if dso:
            assert True
        else:
            self.fail('Save or Find failed')
    
    def test_save_case_9(self):
        """ Tests saving a dso adds it to the latest version map """
        ds_cache = DSCache()
        dso1 = self.get_dummy_saved_dso_1_1()
        ds_cache.save([dso1])
        dso = ds_cache.find_by_id(dso1.id)
        if dso:
            assert True
        else:
            self.fail('Save or Find failed')
    
    def test_save_case_10(self):
        """ Tests saving a dso doesn't add it to the uris map before its initialized """
        ds_cache = DSCache()
        dso1 = self.get_dummy_saved_dso_1_1()
        ds_cache.save([dso1])
        try:
            ds_cache.find_by_URI(dso1.uri)
            self.fail('Find should fail as saving a dso shouldnt add it to the URI map unless the URI map has been initialized')
        except DSCacheNotFoundException:
            assert True
            
    def test_save_case_11(self):
        """ Tests saving a dso adds it to the uris map after its been initialized """
        ds_cache = DSCache()
        dso1_1 = self.get_dummy_saved_dso_1_1()
        dso1_2 = self.get_dummy_saved_dso_1_2()
        # initialize the uris map with one entry
        ds_cache.set_by_URI(dso1_1)
        ds_cache.save([dso1_2])
        dsos = ds_cache.find_by_URI(dso1_1.uri)
        if dsos and len(dsos) == 2:
            assert True
        else:
            self.fail('Save or Find failed')

    def test_save_case_12(self):
        """ Tests saving a dso doesnt add it to the versions map before its initialized """
        ds_cache = DSCache()
        dso1_1 = self.get_dummy_saved_dso_1_1()
        ds_cache.save([dso1_1])
        try:
            ds_cache.find_versions(dso1_1.id)
            self.fail('Find should fail as saving a dso shouldnt add it to the version map unless the map has been initialized')
        except DSCacheNotFoundException:
            assert True
        
    def test_save_case_13(self):
        """ Tests saving a dso adds it to the versions map after its been initialized """
        ds_cache = DSCache()
        dso1_1 = self.get_dummy_saved_dso_1_1()
        dso1_2 = self.get_dummy_saved_dso_1_2()
        # initialize the uris map with one entry
        ds_cache.set_versions(dso1_1.id, [dso1_1.version])
        ds_cache.save([dso1_2])
        dsos = ds_cache.find_versions(dso1_1.id)
        if dsos and len(dsos) == 2:
            assert True
        else:
            self.fail('Save or Find failed')

    def test_set_by_id_and_version_case_1(self):
        """ Tests set dso by id and version in cache """
        ds_cache = DSCache()
        dso1 = self.get_dummy_saved_dso_1_1()
        dso = ds_cache.set_by_id_and_version(dso1)
        if dso and dso1 is dso:
            assert True
        else:
            self.fail('Set failed') 
            
    def test_set_by_id_and_version_case_2(self):
        """ Tests set dso by id and version in cache with no id """
        ds_cache = DSCache()
        dso1 = self.get_dummy_unsaved_dso_1()
        try:
            ds_cache.set_by_id_and_version(dso1)
            self.fail('Shouldnt be able to set a dso by id and version if there is no id')
        except DSCacheException:
            assert True
            
    def test_set_by_id_and_version_case_3(self):
        """ Tests set dso by id and version in cache with no version """
        ds_cache = DSCache()
        dso2 = self.get_dummy_unsaved_dso_2()
        try:
            ds_cache.set_by_id_and_version(dso2)
            self.fail('Shouldnt be able to set a dso by id and version if there is no version')
        except DSCacheException:
            assert True
        
    def test_set_by_id_and_version_case_4(self):
        """ Tests set dso by id and version in cache with no id and version """
        ds_cache = DSCache()
        dso3 = self.get_dummy_unsaved_dso_3()
        try:
            ds_cache.set_by_id_and_version(dso3)
            self.fail('Shouldnt be able to set a dso by id and version if there is no id and version')
        except DSCacheException:
            assert True   
                    
    def test_find_by_id_and_version_case_1(self):
        """ Tests finding a dso by id and version """
        ds_cache = DSCache()
        dso1 = self.get_dummy_saved_dso_1_1()
        ds_cache.save([dso1])
        ds_cache.find_by_id_and_version(dso1.id, dso1.version)

    def test_find_by_id_and_version_case_2(self):
        """ Tests finding a dso by id and version that doesn't exist """
        ds_cache = DSCache()
        try:
            ds_cache.find_by_id_and_version(1, 1)
            self.fail('No dso should be found as cache is empty')
        except DSCacheNotFoundException:
            assert True
    
    def test_find_by_id_and_version_case_3(self):
        """ Tests finding a dso by id and version set in cache """
        ds_cache = DSCache()
        dso1 = self.get_dummy_saved_dso_1_1()
        ds_cache.set_by_id_and_version(dso1)
        ds_cache.find_by_id_and_version(dso1.id, dso1.version) 

    def test_set_by_id_case_1(self):
        """ Tests set dso by id in cache """
        ds_cache = DSCache()
        dso1 = self.get_dummy_saved_dso_1_1()
        dso = ds_cache.set_by_id(dso1)
        if dso and dso1 is dso:
            assert True
        else:
            self.fail('Set failed') 
            
    def test_set_by_id_case_2(self):
        """ Tests set dso by id in cache with no id """
        ds_cache = DSCache()
        dso1 = self.get_dummy_unsaved_dso_1()
        try:
            ds_cache.set_by_id(dso1)
            self.fail('Shouldnt be able to set a dso by id and version if there is no id')
        except DSCacheException:
            assert True
            
    def test_set_by_id_case_3(self):
        """ Tests set dso by id in cache with no version """
        ds_cache = DSCache()
        dso2 = self.get_dummy_unsaved_dso_2()
        try:
            ds_cache.set_by_id(dso2)
            self.fail('Shouldnt be able to set a dso by id and version if there is no version')
        except DSCacheException:
            assert True
        
    def test_set_by_id_case_4(self):
        """ Tests set dso by id in cache with no id and version """
        ds_cache = DSCache()
        dso3 = self.get_dummy_unsaved_dso_3()
        try:
            ds_cache.set_by_id(dso3)
            self.fail('Shouldnt be able to set a dso by id and version if there is no id and version')
        except DSCacheException:
            assert True      
                                    
    def test_find_by_id_case_1(self):
        """ Tests find by id after save"""
        ds_cache = DSCache()
        dso1 = self.get_dummy_saved_dso_1_1()
        dso2 = self.get_dummy_saved_dso_1_2()
        dso3 = self.get_dummy_saved_dso_2_1()
        ds_cache.save([dso1, dso2, dso3])
        dso = ds_cache.find_by_id(1)
        if dso and dso is dso2:
            assert True
        else:
            self.fail('find failed')
            
    def test_find_by_id_case_2(self):
        """ Tests find by id when no entry for id in cache """
        ds_cache = DSCache()
        dso1 = self.get_dummy_saved_dso_1_1()
        ds_cache.save([dso1])
        try:
            ds_cache.find_by_id(2)
            self.fail('DSO id should not be in cache')
        except DSCacheNotFoundException:
            assert True
            
    def test_find_by_id_case_3(self):
        """ Tests find by id when set in cache """
        ds_cache = DSCache()
        dso1_1 = self.get_dummy_saved_dso_1_1()
        dso1_2 = self.get_dummy_saved_dso_1_2()
        ds_cache.set_by_id(dso1_1)
        ds_cache.set_by_id(dso1_2)
        dso = ds_cache.find_by_id(dso1_1.id)
        if dso and dso is dso1_2:
            assert True
        else:
            self.fail('Set or find failed')

    def test_set_by_uri_and_version_case_1(self):
        """ Tests set dso by uri and version in cache """
        ds_cache = DSCache()
        dso1 = self.get_dummy_saved_dso_1_1()
        dso = ds_cache.set_by_URI_and_version(dso1)
        if dso and dso1 is dso:
            assert True
        else:
            self.fail('Set failed') 
            
    def test_set_by_uri_and_version_case_2(self):
        """ Tests set dso by uri and version in cache with no id """
        ds_cache = DSCache()
        dso1 = self.get_dummy_unsaved_dso_1()
        try:
            ds_cache.set_by_URI_and_version(dso1)
            self.fail('Shouldnt be able to set a dso by uri and version if there is no id')
        except DSCacheException:
            assert True
            
    def test_set_by_uri_and_version_case_3(self):
        """ Tests set dso by uri and version in cache with no version """
        ds_cache = DSCache()
        dso2 = self.get_dummy_unsaved_dso_2()
        try:
            ds_cache.set_by_URI_and_version(dso2)
            self.fail('Shouldnt be able to set a dso by uri and version if there is no version')
        except DSCacheException:
            assert True
        
    def test_set_by_uri_and_version_case_4(self):
        """ Tests set dso by uri and version in cache with no id and version """
        ds_cache = DSCache()
        dso3 = self.get_dummy_unsaved_dso_3()
        try:
            ds_cache.set_by_URI_and_version(dso3)
            self.fail('Shouldnt be able to set a dso by uri and version if there is no id and version')
        except DSCacheException:
            assert True   
        
    def test_find_by_uri_and_version_case_1(self):
        """ Tests find by uri and version """
        ds_cache = DSCache()
        dso1 = self.get_dummy_saved_dso_1_1()
        dso2 = self.get_dummy_saved_dso_1_2()
        ds_cache.save([dso1, dso2])
        dso = ds_cache.find_by_URI_and_version(dso1.uri, dso1.version)
        if dso and dso is dso1:
            assert True
        else:
            self.fail('Find failed')
    
    def test_find_by_uri_and_version_case_2(self):
        """ Tests find by uri and version with no match """
        ds_cache = DSCache()
        dso1 = self.get_dummy_saved_dso_1_1()
        ds_cache.save([dso1])
        try:
            ds_cache.find_by_URI_and_version('blah', 2)
            self.fail('find should fail as there is no match for the uri and version in the cache')
        except DSCacheNotFoundException:
            assert True
            
    def test_find_by_uri_and_version_case_3(self):
        """ Tests find by uri and version when set in cache """
        ds_cache = DSCache()
        dso1 = self.get_dummy_saved_dso_1_1()
        ds_cache.set_by_URI_and_version(dso1)
        dso = ds_cache.find_by_URI_and_version(dso1.uri, dso1.version)
        if dso and dso is dso1:
            assert True
        else:
            self.fail('Find or set failed')

    def test_set_by_uri_case_1(self):
        """ Tests set dso by uri in cache """
        ds_cache = DSCache()
        dso1 = self.get_dummy_saved_dso_1_1()
        dso = ds_cache.set_by_URI(dso1)
        if dso and dso1 is dso:
            assert True
        else:
            self.fail('Set failed') 
            
    def test_set_by_uri_case_2(self):
        """ Tests set dso by uri in cache with no id """
        ds_cache = DSCache()
        dso1 = self.get_dummy_unsaved_dso_1()
        try:
            ds_cache.set_by_URI(dso1)
            self.fail('Shouldnt be able to set a dso by uri if there is no id')
        except DSCacheException:
            assert True
            
    def test_set_by_uri_case_3(self):
        """ Tests set dso by uri in cache with no version """
        ds_cache = DSCache()
        dso2 = self.get_dummy_unsaved_dso_2()
        try:
            ds_cache.set_by_URI(dso2)
            self.fail('Shouldnt be able to set a dso by uri if there is no version')
        except DSCacheException:
            assert True
        
    def test_set_by_uri_case_4(self):
        """ Tests set dso by uri in cache with no id and version """
        ds_cache = DSCache()
        dso3 = self.get_dummy_unsaved_dso_3()
        try:
            ds_cache.set_by_URI(dso3)
            self.fail('Shouldnt be able to set a dso by uri if there is no id and version')
        except DSCacheException:
            assert True   
                
    def test_find_by_uri_case_1(self):
        """ Tests find by uris with one uri """
        ds_cache = DSCache()
        dso1 = self.get_dummy_saved_dso_1_1()
        dso2 = self.get_dummy_saved_dso_1_2()
        dso3 = self.get_dummy_saved_dso_2_1()
        ds_cache.save([dso1,dso2,dso3])
        try:
            ds_cache.find_by_URI(dso1.uri)
            self.fail('Should fail as the set_find_by_uri hasnt been called to initialize all dsos for that uri')
        except DSCacheNotFoundException:
            assert True
            
    def test_find_by_uri_case_2(self):
        """ Tests find on a empty cache """
        ds_cache = DSCache()
        try:
            ds_cache.find_by_URI('blah_uri')
            self.fail('Should fail on a empty cache')
        except DSCacheNotFoundException:
            assert True        
    
    def test_find_by_uri_case_3(self):
        """ Tests find by uri with no match """
        ds_cache = DSCache()
        dso1 = self.get_dummy_saved_dso_1_1()
        ds_cache.save([dso1])        
        try:
            ds_cache.find_by_URI('blah_uri')
            self.fail('Should fail when there is not match')
        except DSCacheNotFoundException:
            assert True
    
    def test_find_by_uri_case_4(self):
        """ Tests find by uri set in cache """
        ds_cache = DSCache()
        dso1 = self.get_dummy_saved_dso_1_1()
        ds_cache.set_by_URI(dso1)
        dsos = ds_cache.find_by_URI(dso1.uri)
        if dsos and len(dsos) == 1 and dsos[0] is dso1:
            assert True
        else:
            self.fail('Set or find failed')
            
    def test_find_versions_case_1(self):
        """ Tests find versions """
        ds_cache = DSCache()
        version_number = 1
        versions_list_1 = [1, 2, 3]
        ds_cache.set_versions(version_number, versions_list_1)
        versions_list = ds_cache.find_versions(version_number)
        if versions_list and versions_list is versions_list_1:
            assert True
        else:
            self.fail('Find failed')
    
    def test_find_versions_case_2(self):
        """ Tests find versions with no entry for dso id """
        ds_cache = DSCache()
        try:
            ds_cache.find_versions(1)
            self.fail('Should fail as there is no entry in cache')
        except DSCacheNotFoundException:
            assert True
    
    def test_find_versions_case_3(self):
        """ Tests find versions when no versions for dso id has been set """
        ds_cache = DSCache()
        dso1 = self.get_dummy_saved_dso_1_1()
        ds_cache.save([dso1])
        try:
            ds_cache.find_versions(dso1.id)
            self.fail('Even though the dso was added, if the versions for a dso_id is not set, we should return not found')
        except DSCacheNotFoundException:
            assert True
    
    def test_find_versions_case_4(self):
        """ Tests find versions when dso is added after versions are set """
        ds_cache = DSCache()
        dso1 = self.get_dummy_saved_dso_1_1()
        ds_cache.save([dso1])
        try:
            ds_cache.find_versions(dso1.id)
            self.fail('Shouldnt return any versions')
        except DSCacheNotFoundException:
            ds_cache.set_versions(dso1.id, [dso1.version])
            versions = ds_cache.find_versions(dso1.id)
            if versions and len(versions) == 1 and versions.index(dso1.version) == 0:
                dso2 = self.get_dummy_saved_dso_1_2()
                ds_cache.save([dso2])
                versions = ds_cache.find_versions(dso1.id)
                if versions and len(versions) == 2:
                    assert True
                else:
                    self.fail('find failed')
            else:
                self.fail('find failed')
    
    def test_clear_cache_case_1(self):
        """ Tests clearing the cache """
        ds_cache = DSCache()
        dso1 = self.get_dummy_saved_dso_1_1()
        ds_cache.save([dso1])
        copy_dso1 = ds_cache.find_by_id_and_version(dso1.id, dso1.version)
        if copy_dso1 is dso1:
            ds_cache.clear_cache()
            try:
                ds_cache.find_by_id_and_version(dso1.id, dso1.version)
                self.fail('Cache clear failed')
            except DSCacheNotFoundException:
                # make sure we still have a reference to the dso1 after clearing the cache
                if dso1:
                    assert True
        else:
            self.fail('Find failed')
if __name__ == "__main__":
    #import sys;sys.argv = ['', 'Test.testName']
    unittest.main()